use std::collections::HashMap;
use std::path::Path;
use tera::{Tera, Context};
use crate::{convert::Html, http::HttpContentType};
use crate::server::prelude::*;

#[cfg(feature = "enable-default-logger")]
pub fn init_logger() {
    use tracing_subscriber::EnvFilter;
    use tracing_subscriber::fmt;

    let filter = EnvFilter::try_from_default_env()
        .unwrap_or_else(|_| EnvFilter::new("info"));

    let _ = fmt()
        .with_env_filter(filter)
        .try_init();
}

pub fn render_template<P: AsRef<Path>>(p: P) -> Result<Html<String>, ServerResourceError> {
    let path = Path::new("templates").join(p.as_ref());
    std::fs::read_to_string(path.clone())
        .map(|v| Html(v))
        .map_err(|err| ServerResourceError::new(path, err.to_string()))
}

pub fn render_template_with_vars(
    template_name: &str, 
    vars: &HashMap<&str, String>
) -> Result<Html<String>, ServerResourceError> {
    let tera = Tera::new("templates/**/*").map_err(|e| ServerResourceError::new("", e.to_string()))?;
    let mut context = Context::new();
    for (k, v) in vars.iter() {
        context.insert(*k, v);
    }
    let rendered = tera.render(template_name, &context)
        .map_err(|e| ServerResourceError::new(template_name, e.to_string()))?;
    Ok(Html(rendered))
}

#[get(path = "/static/<file_name>", struct_name = __StaticHandler)]
fn static_file(file_name: String) -> Result<StaticFile, ServerResourceError> {
    let file_path = Path::new("static").join(file_name);

    let ext = file_path
        .extension()
        .and_then(|s| s.to_str())
        .unwrap_or("")
        .to_lowercase();

    let content_type = HttpContentType::from_extension(&ext);
    
    let content = std::fs::read(file_path.clone())
        .map_err(|err| ServerResourceError::new(file_path, err.to_string()))?;

    Ok(StaticFile { content, content_type} )
}

pub struct StaticFile {
    pub content: Vec<u8>,
    pub content_type: HttpContentType,
}

impl IntoResponse for StaticFile {
    fn status_code(&self) -> u16 {
        200
    }

    fn content_type(&self) -> HttpContentType {
        self.content_type.clone()
    }

    fn into_body(self) -> Vec<u8> {
        self.content
    }
}